6章 クラスの作成
tommy.icon 6.3 まで
プログラムの見地はステートメント→ルーチン→クラスと遷移していった
6.1 クラスの基礎:抽象データ型(ADT)
抽象データ型
ADTの話題は数学的になり眠い話になりがちだが実際はとても刺激的なもの ADTの利点
実装の詳細を隠蔽
変更が全体に影響しない
インターフェイスが提供する情報が明確
パフォーマンスを改善しやすい
正しさが際立つ
ひとめでわかる
あちこちでのデータのやり取りが不要
現実世界のエンティティを扱える
tommy.icon ADTの定義がよく解らないのでWikipediaで調べた
データ構造とそれを直接操作する手続きをまとめてデータ型の定義とすることでデータ抽象を実現する手法またはそのひとまとまりとして定義されたデータ型を言う。
なるほど、データ構造と手続をまとめたものか
ADTのその他の例
下位レベルのデータ型を最上位に抽象化できる
ファイルなどもADTとして扱える
単純な項目も扱う
格納媒体から独立させる
akht.icon 抽象化されるとreadメソッドが実はDBからの重いアクセスだったなんてこともありそう
qst_exe.icon 同じgetRankingでRedisとDB使い分けたりしてた(ランキング取得が激重)
クラスは「ADT+継承およびポリモーフィズム」として考えることもできる
tommy.icon なるほど〜
6.2 良いクラスインターフェイス
tommy.icon 良い抽象化の例解りやすい
どのクラスでも、ADTは1つだけ実装すべきである
「継承は『is a』関係のみに使用されているか
サービスは逆のサービスと2つ1組にする
意味的なものでなくプログラム的なものにする
6.2.2 良いカプセル化
「インターフェイスの抽象化の整合性を最も維持するものはどれか」でアクセス制限を選ぶ
tommy.icon なるほど〜
判断がつかない場合は少し隠すよりも多めに隠す
書き手の便宜よりも読み手の便宜
tommy.icon 頷くしかない
インターフェイスを通じてプログラミングすれば、カプセル化は崩壊する
実装に対してプログラミングしてはならない
6.3 設計と実装の問題
6.3.1 包含 (has a)
tommy.icon コンポジションとも言われるやつかな
取り上げられる機会が少ないが継承の方が良いというわけではない
継承のほうが難解でエラーの原因になりやすいため
tommy.icon 確かにプログラミング言語入門の本で継承については良く出るけど包含については触れられること少ないイメージ
tommy.icon プライベート継承なんて手法があるのか
メンバデータは7プラスマイナス2個が良い
6.3.2 継承 (is a)
基底クラスが定義したインターフェイス規約に完全に従わないなら継承は正しくない
LSP (リスコフの置換原則)
階層は2〜3段階以上になっただけで整理できなくなる
多重継承は危険なためミックスインを使う
6.3.3 メンバルーチンとメンバデータ
デメテルの法則
6.3.4 コンストラクタ
すべてのコンストラクタですべてのメンバデータを初期化することで防御的になる
tommy.icon ほー
シャローコピーを使用すべき根拠が明確になるまではディープコピーを使う
ディープコピーのほうがコーディングや保守が容易なため
qst exe.icon 6.4 から
6.4 クラスを作成する理由
クラスを作成する理由は現実世界のオブジェクトをモデリングすることだけと思われるがそうではない
現実世界のオブジェクトをモデリングする
例については6.1を参照
抽象オブジェクトをモデリングする
Shapeオブジェクト(円や四角形は現実に存在するが、図形は抽象概念である)
現実世界の具体的な物体から抽象的な概念を引き出すプロセスは、ルールがあるわけでなく、設計者によってまちまちである
複雑さの緩和
最初の設計こそ大変なものの、一度クラスを作成してしまえば、詳細や内部の仕組みを気にしなくてよくなる
複雑さの分離
複雑さはどんな形であってもエラーの原因になりやすい
エラーが発生したときに適度にクラスによって分離されていると、修正が発見しやすく、影響範囲も小さい(疎結合の場合のみかな)
アルゴリズムがクラスに分離されていると、より最適なアルゴリズムが見つかったときに分離しやすい
実装の詳細を隠蔽する
データベースアクセス
広告やアプリ内課金
広告会社毎に提供しているAPIが違うので、独自クラスを作って隠蔽したりした qst_exe.icon
変更による影響を限定する
グローバルデータを隠蔽する
引数の受け渡しを合理化する
制御を一元化する
テーブルのエントリ数を調べる
ファイルやデータベースアクセス
情報隠蔽に似ているがヒューリスティクスに威力を発揮するので、テクニックとして覚えておくと良さそう
コードの再利用を促進する
NASAの調査によると70%のコードは再利用可能とのこと
プログラムのファミリを計画する
プログラムの変更が予想される箇所は、該当箇所をクラスとして独立させる
関連する操作をパッケージにまとめる
三角関数、統計関数、文字列操作等
特定のリファクタリングを実行する
6.4.1 望ましくないクラス
ゴッド(God)クラスを作成しない
他のクラスの領域に色々と口を出さない
不適切なクラスを削除する
クラスの名前を動詞にしない
データだけで構成されていて、振る舞いが定義されていないクラスは他のクラスの属性にすることを検討する
振る舞いだけで構成されていて、データが定義されていないクラスは他のクラスのメンバルーチンにすることを検討する
こちらは割とありそうな気がするがどうだろうかqst_exe.icon
6.4.2 クラスを作成する理由のまとめ
6.4の概要のまとめ
6.5 言語固有の問題
Javaの場合は派生クラスにおいて全てのルーチンがオーバーライドされる
C++ではルーチンは既定ではオーバーライドされない
Visual Basicでは基底クラスでルーチンをOverridableで宣言し、Overrideキーワードを使用しなければならない
※ 細かくは章末の参考資料をいること
6.6 クラスを超えて:パッケージ
執筆時時点ではクラスはプログラマがモジュール化を実現するための最も効果的な手段である(おそらくは今も)
パッケージをサポートしていない言語でプログラミングしている場合は、自分専用のパッケージを作成して適用すれば良い
パッケージに含まれているパブリックなクラスとプライベートなクラスを区別する命名規則
どのクラスがどのパッケージに属しているのかを識別する命名規則、プロジェクト構造
他のパッケージを使用できるパッケージと、その使用方法が継承、包含、またはその両方のいずれであるかを定義する規則
クラス品質のチェックリスト
抽象データ型
抽象化
カプセル化
継承
その他の実装問題
言語固有の問題
6.7 巻末資料
クラス全般と言語ごと(C++, Java, Visual Basic)にまとめてあるので、いつか読んでみたい
「Effective Java - プログラミング言語ガイド」は良い本と聞いたことあるけど読んだことない…qst_exe.icon
いい本らしい
6.8 まとめ
クラスインターフェイスは一貫性のある抽象化を実現しなければならない
クラスインターフェイスは何かを隠蔽しなければならない
「is a」関係をモデリングする場合を除き、通常は継承よりも包含の方が望ましい
継承は便利なツールだが、複雑さを増大させる。
クラスは複雑さに対処するための第一ツールである。